﻿using System;
using System.Collections.ObjectModel;
using MugenInjection.Delegates;

namespace MugenInjection.Infrastructure
{
    /// <summary>
    /// Represents a collection which support notify events.
    /// </summary>
    internal sealed class NotifyCollectionImpl<T> : Collection<T>
    {
        #region Events

        public event Action<T> Added;

        public event Action<T, T> Changed;

        public event Action<T> Removed;

        private void OnAdded(T obj)
        {
            Action<T> handler = Added;
            if (handler != null) handler(obj);
        }

        private void OnChanged(T arg1, T arg2)
        {
            Action<T, T> handler = Changed;
            if (handler != null) handler(arg1, arg2);
        }

        private void OnRemoved(T obj)
        {
            Action<T> handler = Removed;
            if (handler != null) handler(obj);
        }

        #endregion

        #region Overrides of Collection<T>

        /// <summary>
        /// Removes all elements from the <see cref="T:System.Collections.ObjectModel.Collection`1"/>.
        /// </summary>
        protected override void ClearItems()
        {
            for (int index = 0; index < Items.Count; index++)
                OnRemoved(Items[index]);
            base.ClearItems();
        }

        /// <summary>
        /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1"/> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.
        ///                 </param><param name="item">The object to insert. The value can be null for reference types.
        ///                 </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.
        ///                     -or-
        ///                 <paramref name="index"/> is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        ///                 </exception>
        protected override void InsertItem(int index, T item)
        {
            base.InsertItem(index, item);
            OnAdded(item);
        }

        /// <summary>
        /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1"/>.
        /// </summary>
        /// <param name="index">The zero-based index of the element to remove.
        ///                 </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.
        ///                     -or-
        ///                 <paramref name="index"/> is equal to or greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        ///                 </exception>
        protected override void RemoveItem(int index)
        {
            OnRemoved(this[index]);
            base.RemoveItem(index);
        }

        /// <summary>
        /// Replaces the element at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the element to replace.
        ///                 </param><param name="item">The new value for the element at the specified index. The value can be null for reference types.
        ///                 </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.
        ///                     -or-
        ///                 <paramref name="index"/> is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        ///                 </exception>
        protected override void SetItem(int index, T item)
        {
            OnChanged(this[index], item);
            base.SetItem(index, item);
        }

        #endregion
    }
}